什么是端序
端序,也叫字节序,是指计算机上多字节数据类型的存储规则。在日常的编码中可能不太需要关心端序,但当涉及到一些比较底层的任务,例如 socket 编程时,就绕不开它。
端序(Endian)有两种规则,一种是大端序,一种是小端序。大端序是指将高位字节存放在低位地址,而小端序则是将低位字节存放在低位地址。
以0x01234567
为例。
大端序:
低地址 | 高地址 | ||
---|---|---|---|
0x01 | 0x23 | 0x45 | 0x67 |
小端序:
低地址 | 高地址 | ||
---|---|---|---|
0x67 | 0x45 | 0x23 | 0x01 |
iOS上的端序
目前为止,iOS 上采用的端序是小端序。在 NSByteOrder.h 和 OSByteOrder.h 中有许多和端序相关的定义,其中当前系统的端序可以通过 NSHostByteOrder()
获取到:
1 | if (NSHostByteOrder() == NS_BigEndian) { |
端序的转换
不同的设备或协议可能采用不同的端序,例如,iPhone 和 x86 架构的 PC 都采用小端序,USB协议也采用小端序;而许多网络协议,如 TCP/IP 协议,以及部分 PC 则采用大端序。此外,ARM 等平台的端序则是可以配置的。因此,当涉及到 socket、信号处理等比较底层的操作时,我们需要注意不同场合下所需的端序,按需进行转换。
不同的语言中通常都有对应的 ntoh*
和 hton*
方法,来进行端序的转换。TCP/IP 协议中规定了数据采用大端序,因此大端序也常常被称作网络端序。相反地,小端则被称作主机端序。这也是我们常常见到的端序转换方法名 ntoh*
(network-to-host)、hton*
(host-to-network) 的由来。
1 | // 转换端口号的端序 |
根据数据的字节数的不同,Darwin 为我们提供了一系列常用的宏来转换端序:ntohs
(16bits)、ntohl
(32bits)、ntohll
(64bits)、htons
(16bits)、htonl
(32bits)、htonll
(64bits).如果需要进行更长字节数的端序转换,则需要我们自己实现。
1 | // Int16 的端序转换宏 |
1 | // 常量的端序转换方法,在预处理阶段完成(uint16) |
1 | // 运行时的端序转换方法(uint16) |
查看这些宏的定义可以发现,Darwin 会先判断待转换的数据是否常量,如果是常量,则直接进行移位运算,在编译前的预处理阶段就完成转换;如果是变量,则替换为相应的内联方法,在运行时进行转换。